﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

/*For observable collection */
using System.Collections.ObjectModel;

/* Threading */
/* Synchronized methods */
using System.Threading;
using System.Runtime.CompilerServices;

using GasData;

namespace WPF_DataLogger
{
    public partial class MRFDecoder: PackDecoder
    {
        public MRFDecoder()
        {
            decoder_type = DecoderType.MRF;
            this.FormatPacket();
        }

        public MRFDecoder(byte[] packet)
        {
            if (packet != null)
            {
                CopyPacket(packet);

                decoder_type = DecoderType.MRF;
            }

            FormatPacket();
        }

        public override double GetTemp()
        {
            int integer_value;

            integer_value = TwoBytesToInt(temp_pos);

            return integer_value / 3.3;
        }

        public override double GetHumid()
        {
            return 0.0;
        }

        public override int GetGasNum()
        {
            return _packet[gas_num_pos];
        }


        private bool IsPreambleOK()
        {
            for (int i = 0; i < MRF_PREAMBLE_LEN - 1; i++)
            {
                if (_packet[i] != PREAMBLE_DATA)
                    return false;
            }

            if (_packet[MRF_PREAMBLE_LEN - 1] != PREAMBLE_END)
                return false;

            return true;
        }

        public override bool IsHeaderCorrect
        {
            get
            {
                if (_packet == null)
                {
                    throw new NullReferenceException("MRFDecoder: _packet is null.");
                }

                if (_packet.Length < pack_len_pos + 1)
                {

                    throw new IndexOutOfRangeException("MRFDecoder: not big enough _packet length");
                }

                if (!IsPreambleOK())
                {
                    return false;
                }

                return true;
            }
        }

        public override int HeaderLength
        {
            get
            {
                return pack_len_pos + 1;
            }
        }



        public override ObservableCollection<GasInfo> GetGasList(List<string> gas_name_list, SensorFamily family)
        {
            ObservableCollection<GasInfo> ret = new ObservableCollection<GasInfo>();

            int next_gas_idx = gas_base_pos;
            int shift_pos = INIT_SHIFT_BITS;

            if (_packet == null)
            {
                NullReferenceException ex = new NullReferenceException("_packet is null.");
                throw ex;
            }

            if (gas_name_list == null)
            {
                throw new NullReferenceException("Gas name list null");
            }

            for (int i = 0; i < _packet[gas_num_pos] && i < gas_name_list.Count;
                i++, next_gas_idx++, shift_pos += SHIFT_STEP)
            {
                int temp_value = GetGasInt(next_gas_idx, shift_pos);

                double next_gas_value = GetGasValue(temp_value, gas_name_list[i],family);

                GasInfo new_gas_info = new GasInfo();

                new_gas_info.Gas_name = gas_name_list[i];
                new_gas_info.Cur_val = next_gas_value;

                ret.Add(new_gas_info);
            }


            return ret;

        }


        public override int PackPayloadLen
        {
            get
            {
                if (_packet == null)
                {
                    throw new NullReferenceException("MRFDecoder: _packet is null.");
                }

                if (_packet.Length < pack_len_pos + 1)
                {

                    throw new IndexOutOfRangeException("MRFDecoder: not big enough _packet length");
                }

                if (_packet.Length < _packet[pack_len_pos] + pack_len_pos + 1)
                {
                    throw new IndexOutOfRangeException("MRFDecoder: not big enough _packet length");
                }

                return _packet[pack_len_pos];
            }
        }

        public override int SensorFieldLength
        {
            get
            {
                if (_packet != null)
                {
                   return _packet[gas_num_pos] + 1;
                }
                else
                {
                    throw new System.NullReferenceException("decoder: data packet is null");
                }
            }
        }

        public override int PreambleLength
        {
            get
            {
                return preamble_len;
            }
        }

        public override int PacketTailLength
        {
            get
            {
                return 0;
            }
        }

        public override bool IsPreambleData(byte data)
        {
            if (data == PREAMBLE_DATA)
                return true;

            return false;
        }

        public override bool IsPreambleEnd(byte data)
        {
            if (data == PREAMBLE_END)
                return true;

            return false;
        }

        protected int GetGasInt(int pos, int shift_bits)
        {
            int max_mask_bits = 6;
            byte mask = (byte)(0xFF >> (max_mask_bits - shift_bits));

            byte higher_bits = (byte)(_packet[pos + 1] & mask);

            return ((((int)higher_bits) << 8) | _packet[pos]) >> shift_bits;
        }

        protected override void FormatPacket()
        {
            temp_pos = MRF_TEMP_POS;
            humid_pos = MRF_HUMID_POS;
            gps_time_hour = MRF_GPS_TIME_HOUR;
            gps_time_min = MRF_GPS_TIME_MIN;
            gps_time_sec = MRF_GPS_TIME_SEC;
            gps_longitude = MRF_GPS_LONGITUDE;
            gps_latitude = MRF_GPS_LATITUDE;
            node_id_pos = MRF_NODE_ID_POS;
            gas_num_pos = MRF_GAS_NUM_POS;
            gas_base_pos = MRF_GAS_BASE_POS;
            pack_len_pos = MRF_PACK_LEN_POS;
            preamble_len = MRF_PREAMBLE_LEN;
            pack_type_pos = MRF_PACK_TYPE_POS;
            _adc_max_value = MRF_ADC_MAX_VALUE;
        }

        const int MRF_TEMP_POS = 7;
        const int MRF_HUMID_POS = 9;
        const int MRF_GPS_TIME_HOUR = 11;
        const int MRF_GPS_TIME_MIN = 12;
        const int MRF_GPS_TIME_SEC = 13;
        const int MRF_GPS_LONGITUDE = 14;
        const int MRF_GPS_LATITUDE = 16;
        const int MRF_NODE_ID_POS = 5;
        const int MRF_GAS_NUM_POS = 18;
        const int MRF_GAS_BASE_POS = 19;
        const int MRF_PREAMBLE_LEN = 4;
        const int MRF_PACK_LEN_POS = 6;
        const int MRF_PACK_TYPE_POS = 4;
        const int MRF_ADC_MAX_VALUE = 1024;

        const int INIT_SHIFT_BITS = 0;
        const int SHIFT_STEP = 2;

        const int PREAMBLE_DATA = 0x55;
        const int PREAMBLE_END = 0x5B;
    }
}
